// 对axios的封装 index.ts作为统一出口
import axios from 'axios'
// 导入类型
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
// 导入环境进行区分
import { BASE_URL, TIME_OUT } from './区分环境'

// 注意: 不是使用<el-xxx> 就单独导入需要的css
import { ElLoading } from 'element-plus'
import 'element-plus/es/components/loading/style/css'

// el-loading的类型 LoadingInstance
import { LoadingInstance } from 'element-plus/lib/components/loading/src/loading'

import LocalCache from '@/utils/cache'

interface interceptRq<T = AxiosResponse> {
  interceptRequest?: (config: AxiosRequestConfig) => AxiosRequestConfig
  interceptRequesterr?: (err: any) => any
  interceptResponse?: (res: T) => T
  interceptResponseerr?: (err: any) => any
}

interface RequestConfig<T = AxiosResponse> extends AxiosRequestConfig {
  interceptors?: interceptRq<T>
  showLoading?: boolean
}

// 类的封装性更强，比你多次导出函数强
class Request {
  instance: AxiosInstance
  interceptors?: interceptRq
  showLoading: boolean
  loading?: LoadingInstance

  constructor(config: RequestConfig) {
    // 创建axios实例
    this.instance = axios.create(config)
    // 保存基本信息
    this.interceptors = config.interceptors
    this.showLoading = config.showLoading ?? true

    // 使用了拦截器
    // 创建当前实例的拦截器(自己)
    this.instance.interceptors.request.use(
      this.interceptors?.interceptRequest,
      this.interceptors?.interceptRequesterr
    )
    this.instance.interceptors.response.use(
      this.interceptors?.interceptResponse,
      this.interceptors?.interceptResponseerr
    )

    // 添加所有的实例拦截器
    this.instance.interceptors.request.use((config) => {
      // console.log('所有的请求成功拦截器')

      // 是否显示loading
      if (this.showLoading) {
        // 请求时添加loading
        this.loading = ElLoading.service({
          lock: true,
          text: 'Fhup努力加班中',
          background: 'rgba(0,0,0,.5)'
        })
      }

      return config
    })

    this.instance.interceptors.response.use(
      (res) => {
        // console.log('所有的响应成功拦截器')
        // 响应成功将loading移除
        this.loading?.close()
        return res
      },
      (err) => {
        // 响应失败也将loading移除
        this.loading?.close()
        // 对错误信息进行处理
        return err
      }
    )
  }
  // 自己的方法
  requsetinfo<T = any>(config: RequestConfig<T>): Promise<T> {
    return new Promise((resolve, reject) => {
      // 单个请求对拦截器的处理
      if (config.interceptors?.interceptRequest) {
        config = config.interceptors.interceptRequest(config)
      }

      // 判断是否显示loading 你传入false或者true必须进去设置this.showLoading的值
      if (config.showLoading === false || config.showLoading === true) {
        this.showLoading = config.showLoading
      }

      this.instance
        .request<any, T>(config)
        .then((res) => {
          // 单个请求对数据的处理
          if (config.interceptors?.interceptResponse) {
            res = config.interceptors.interceptResponse(res)
          }
          // 将结果resolve返回出去,用then处理
          resolve(res)
        })
        .catch((err) => {
          reject(err)
        })
    })
  }
  get<T = any>(config: RequestConfig<T>): Promise<T> {
    return this.requsetinfo<T>({
      ...config,
      method: 'GET'
    })
  }
  post<T = any>(config: RequestConfig<T>): Promise<T> {
    return this.requsetinfo<T>({
      ...config,
      method: 'POST'
    })
  }
  delete<T = any>(config: RequestConfig<T>): Promise<T> {
    return this.requsetinfo<T>({
      ...config,
      method: 'DELETE'
    })
  }
  // 修改数据 patch请求
  patch<T = any>(config: RequestConfig<T>): Promise<T> {
    return this.requsetinfo<T>({
      ...config,
      method: 'PATCH'
    })
  }
}

const request = new Request({
  baseURL: BASE_URL,
  timeout: TIME_OUT,
  interceptors: {
    interceptRequest(config) {
      // 获取token,对携带的token的拦截
      const token = LocalCache.getCache('token')
      // ! 表示必须有值
      if (token) {
        config.headers!.Authorization = `Bearer ${token}`
      }
      // console.log('请求成功拦截')
      return config
    },
    interceptRequesterr(err) {
      // console.log('请求失败拦截')
      return err
    },
    interceptResponse(res) {
      // console.log('响应成功拦截')
      return res.data
    },
    interceptResponseerr(err) {
      // console.log('响应失败拦截')
      return err
    }
  }
})

export default request
